#pragma once

#ifndef MESH_LOADER_HPP
#define MESH_LOADER_HPP

#include "Math.hpp"
#include <assimp/Importer.hpp>
#include <assimp/postprocess.h>
#include <assimp/scene.h>

#include <memory>
#include <vector>

namespace Data {
struct Vertex {
  glm::vec3 position;
  glm::vec3 normal;
  glm::vec2 texCoords;
  glm::vec3 color;
  glm::vec3 biTangent;
  glm::vec3 tangent;
};

static constexpr auto POSITION_OFFSET = offsetof(Vertex, position);
static constexpr auto NORMAL_OFFSET = offsetof(Vertex, normal);
static constexpr auto TEXCOORS_OFFSET = offsetof(Vertex, texCoords);
static constexpr auto COLOR_OFFSET = offsetof(Vertex, color);
static constexpr auto BITANGENT_OFFSET = offsetof(Vertex, biTangent);
static constexpr auto TANGET_OFFSET = offsetof(Vertex, tangent);
static constexpr auto VERTEX_STRIDE = sizeof(Vertex);

static constexpr uint32_t VERTEX_FORMAT_OFFSET[] = {
    offsetof(Vertex, position),
    offsetof(Vertex, normal),
    offsetof(Vertex, texCoords),
    offsetof(Vertex, color),
    offsetof(Vertex, biTangent),
    offsetof(Vertex, tangent),
    sizeof(Vertex),
};

class Mesh;
class ModelObject;

class MeshLoader {
  // Null terminated string
public:
  MeshLoader(ModelObject *model) : _model(model) {}
  void LoadMeshFromFile(const char *fileName);

private:
  ModelObject *_model = nullptr;
  void ProcessNode(aiNode *node, const aiScene *scene);
  void ProcessMesh(aiMesh *mesh, const aiScene *scene);
};

class Mesh {
private:
  Mesh(const std::vector<Vertex> &v, const std::vector<uint32_t> &i)
      : vertices(std::move(v)), indices(std::move(i)) {}

public:
  const void *getIndicesRawData() const { return indices.data(); }
  const void *getVertexRawData() const { return vertices.data(); }

  auto getIndicesCount() const { return indices.size(); }
  auto getVertexCount() const { return vertices.size(); }

  friend class ModelObject;

  ~Mesh() {
    vertices.clear();
    indices.clear();
  }

private:
  std::vector<Vertex> vertices;
  // TODO: Current Only support 32bit integer indices type
  std::vector<uint32_t> indices;
};

} // namespace Data

#endif
